/* jslight -- Lua highlighter */
/* Copyright 2007 Rici Lake. */
/* You may use this software under the terms of the MIT license
 * as shown at http://www.opensource.org/licenses/mit-license.php
 */

if (!this.jslight) {this.jslight = {"language":{}}; }
(function() {
  jslight.language.lua = {}

  // TODO: Replace this with jslight.addAnnotations
  var words = {
  /* Reserved */
         "and": "operator",  "break": "statement",    "do": "statement",   "else": "conditional",
      "elseif": "conditional", "end": "statement", "false": "constant",     "for": "repeat",
    "function": "identifier",   "if": "conditional",  "in": "repeat",     "local": "statement",
         "nil": "constant",    "not": "operator",     "or": "operator",  "repeat": "statement",
      "return": "statement",  "then": "conditional","true": "constant",   "until": "repeat",
       "while": "repeat",
  /* Symbols */
    "+": "none",  "-": "none",  "*": "none",  "/": "none",  "^": "none",  "%": "none",
    "#": "none",  "=": "none",  ",": "none",  ";": "none",  ".": "none",  ":": "none",
    "(": "none",  ")": "none",  "[": "none",  "]": "none",  "{": "type",  "}": "type",
  /* Known identifiers */
        "_G": "identifier", "_VERSION": "identifier",   "assert": "identifier", "collectgarbage": "identifier",
    "dofile": "identifier",    "error": "identifier",  "getfenv": "identifier",   "getmetatable": "identifier",
    "ipairs": "identifier",     "load": "identifier", "loadfile": "identifier",     "loadstring": "identifier",
    "module": "identifier",     "next": "identifier",    "pairs": "identifier",          "pcall": "identifier",
     "print": "identifier", "rawequal": "identifier",   "rawget": "identifier",         "rawset": "identifier",
   "require": "identifier",   "select": "identifier",  "setfenv": "identifier",   "setmetatable": "identifier",
  "tonumber": "identifier", "tostring": "identifier",     "type": "identifier",         "unpack": "identifier",
    "xpcall": "identifier",

  "coroutine": "identifier",
   "coroutine.create": "identifier", "coroutine.resume": "identifier",  "coroutine.running": "identifier",
   "coroutine.status": "identifier",   "coroutine.wrap": "identifier",    "coroutine.yield": "identifier",

  "debug": "identifier",
        "debug.debug": "identifier",    "debug.getfenv": "identifier",      "debug.gethook": "identifier",
      "debug.getinfo": "identifier",   "debug.getlocal": "identifier", "debug.getmetatable": "identifier",
  "debug.getregistry": "identifier", "debug.getupvalue": "identifier",      "debug.setfenv": "identifier",
      "debug.sethook": "identifier",   "debug.setlocal": "identifier", "debug.setmetatable": "identifier",
   "debug.setupvalue": "identifier",  "debug.traceback": "identifier",

  "io": "identifier",
    "io.close": "identifier",  "io.flush": "identifier",   "io.input": "identifier",   "io.lines": "identifier",
     "io.open": "identifier", "io.output": "identifier",   "io.popen": "identifier",    "io.read": "identifier",
   "io.stderr": "identifier",  "io.stdin": "identifier",  "io.stdout": "identifier", "io.tmpfile": "identifier",
     "io.type": "identifier",  "io.write": "identifier", 

  "math": "identifier",
    "math.abs": "identifier", "math.acos": "identifier",  "math.asin": "identifier",  "math.atan": "identifier",
  "math.atan2": "identifier", "math.ceil": "identifier",   "math.cos": "identifier",  "math.cosh": "identifier",
    "math.deg": "identifier",  "math.exp": "identifier", "math.floor": "identifier",  "math.fmod": "identifier",
  "math.frexp": "identifier", "math.huge": "identifier", "math.ldexp": "identifier",   "math.log": "identifier",
  "math.log10": "identifier",  "math.max": "identifier",   "math.min": "identifier",  "math.modf": "identifier",
     "math.pi": "identifier",  "math.pow": "identifier",   "math.rad": "identifier","math.random": "identifier",
                        "math.randomseed": "identifier",   "math.sin": "identifier",  "math.sinh": "identifier",
   "math.sqrt": "identifier",  "math.tan": "identifier",  "math.tanh": "identifier", 

  "os": "identifier",
    "os.clock": "identifier",   "os.date": "identifier","os.difftime": "identifier", "os.execute": "identifier",
     "os.exit": "identifier", "os.getenv": "identifier",  "os.remove": "identifier",  "os.rename": "identifier",
                           "os.setlocale": "identifier",    "os.time": "identifier", "os.tmpname": "identifier",
   
  "package": "identifier",
    "package.cpath": "identifier", "package.loaded": "identifier", "package.loaders": "identifier",
  "package.loadlib": "identifier",   "package.path": "identifier", "package.preload": "identifier",
   "package.seeall": "identifier",

  "string": "identifier",
      "string.byte": "identifier",    "string.char": "identifier",     "string.dump": "identifier",
      "string.find": "identifier",  "string.format": "identifier",   "string.gmatch": "identifier",
      "string.gsub": "identifier",     "string.len": "identifier",    "string.lower": "identifier",
     "string.match": "identifier",     "string.rep": "identifier",  "string.reverse": "identifier",
       "string.sub": "identifier",   "string.upper": "identifier",

  "table": "identifier",
     "table.concat": "identifier",   "table.insert": "identifier",      "table.maxn": "identifier",
     "table.remove": "identifier",     "table.sort": "identifier"
  };

  function pushReturn(stack, m)  { stack.push(m); return jslight.annotate(m, words[m]); }
  function pushReturn2(stack, m) { stack.push(m, "od"); return jslight.annotate(m, words[m]); }

  var actions = {
    "for": pushReturn2,
    "while": pushReturn2,
    "function": pushReturn,
    "if": pushReturn,
    "do": function(stack, m) {
            if (stack && stack[stack.length-1] === "od") {
              stack.pop();
              return jslight.annotate(m, words[stack[stack.length-1]]);
            }
            else return pushReturn(stack, m);
          },
    "end": function(stack, m) {
             var top = stack.pop();
             var t = "error";
             if (top === "od") stack.pop();
             else if (top) t = words[top];
             return jslight.annotate(m, t);
           }
  }
  /* We construct a single regular expression which matches every possible lexeme.
   * 1: whitespace  2: comments    3: unused      4: strings     5: unused
   * 6: numbers     7: words       8: multichar symbols          9: anything else including error
   */
  var lex = /(\s+)|(-\-(?:\[(=*)\[[\s\S]*?\]\3\]|.*))|("(?:[^\\"\r\n]|\\(?:.|\r?\n))*"|'(?:[^\\'\r\n]|\\(?:.|\r?\n))*'|\[(=*)\[[\s\S]*?\]\5\])|((?:\d+(?:\.\d*)?|\.\d+)(?:[Ee][+-]?\d+)?|0[Xx][0-9a-fA-F]+)|([a-zA-Z_][\w_]*(?:\.[a-zA-Z_][\w_]*)*)|(\.{1,3}|(?:&[lg]t;|=)=?|~=)|(&\w+;|\[=*\[|.)/g;

  jslight.language.lua.getHighlighter = function() {
    var stack = [];

    function highlightLexeme(m, a1, a2, a3, a4, a5, a6, a7, a8, a9) {
      if (a1) return jslight.annotate(m);
      else if (a2) return jslight.annotate(m, "comment");
      else if (a4 || a6) return jslight.annotate(m, "constant");
      else if (a7) {
        if (m in actions) return actions[m](stack, m);
        else if (m in words) return jslight.annotate(m, words[m]);
        else {
          r = m.split(/\./)[0];
          if (r in words) return jslight.annotate(r, words[r])+m.slice(r.length);
          else return jslight.annotate(m);
        }
      }
      else if (a8) return jslight.annotate(m);
      else return jslight.annotate(m, words[m] || "error");
    }

    return function(s) {
      return s.replace(lex, highlightLexeme);
    }
  }
})()
